// NetworkCollector.ts - 网络请求采集器
// @/utils/monitor/collectors/NetworkCollector.ts

import { MonitorEventBus } from '../core/MonitorEventBus';
import { MonitorConfig, EventType, ApiEventData, ICollector } from '../MonitorTypes';

interface RequestInfo {
  method: string;
  url: string;
  headers?: Record<string, string>;
  body?: any;
  startTime: number;
}

/**
 * 网络请求采集器
 * 拦截XMLHttpRequest、fetch、uni.request等网络请求，收集性能和错误信息
 */
export class NetworkCollector implements ICollector {
  public readonly name = 'NetworkCollector';
  
  private eventBus: MonitorEventBus;
  private config: MonitorConfig;
  private requestMap: WeakMap<any, RequestInfo>;
  private isStarted: boolean = false;
  private cleanup: Array<() => void> = [];
  
  // 保存原始方法
  private originalXHR: {
    open?: typeof XMLHttpRequest.prototype.open;
    send?: typeof XMLHttpRequest.prototype.send;
    setRequestHeader?: typeof XMLHttpRequest.prototype.setRequestHeader;
  } = {};
  private originalFetch?: typeof window.fetch;
  private originalUniRequest?: typeof uni.request;

  constructor(eventBus: MonitorEventBus, config: MonitorConfig) {
    this.eventBus = eventBus;
    this.config = config;
    this.requestMap = new WeakMap();
  }

  /**
   * 初始化采集器
   */
  public init(config: MonitorConfig): void {
    this.config = config;
  }

  /**
   * 启动网络请求采集
   */
  public start(): void {
    if (this.isStarted) {
      return;
    }

    this.interceptXHR();
    this.interceptFetch();
    this.interceptUniRequest();
    
    this.isStarted = true;

    if (this.config.enableDebug) {
      console.log('[NetworkCollector] Started network tracking');
    }
  }

  /**
   * 停止网络请求采集
   */
  public stop(): void {
    if (!this.isStarted) {
      return;
    }

    this.restoreOriginalMethods();
    
    // 清理所有回调
    this.cleanup.forEach(fn => fn());
    this.cleanup = [];
    
    this.isStarted = false;

    if (this.config.enableDebug) {
      console.log('[NetworkCollector] Stopped network tracking');
    }
  }

  /**
   * 销毁采集器
   */
  public destroy(): void {
    this.stop();
  }

  /**
   * 拦截XMLHttpRequest
   */
  private interceptXHR(): void {
    // #ifdef H5
    if (typeof XMLHttpRequest === 'undefined') {
      return;
    }

    const self = this;
    const XMLHttpRequestPrototype = XMLHttpRequest.prototype;
    
    // 保存原始方法
    this.originalXHR.open = XMLHttpRequestPrototype.open;
    this.originalXHR.send = XMLHttpRequestPrototype.send;
    this.originalXHR.setRequestHeader = XMLHttpRequestPrototype.setRequestHeader;
    
    // 拦截 open 方法
    XMLHttpRequestPrototype.open = function(
      method: string,
      url: string | URL,
      async?: boolean,
      username?: string | null,
      password?: string | null
    ): void {
      const urlString = url.toString();
      
      // 过滤监控上报请求
      if (urlString.includes(self.config.endpoint)) {
        return self.originalXHR.open!.apply(this, arguments as any);
      }
      
      // 保存请求信息
      self.requestMap.set(this, {
        method,
        url: urlString,
        headers: {},
        startTime: Date.now()
      });
      
      return self.originalXHR.open!.apply(this, arguments as any);
    };
    
    // 拦截 setRequestHeader 方法
    XMLHttpRequestPrototype.setRequestHeader = function(
      name: string,
      value: string
    ): void {
      const requestInfo = self.requestMap.get(this);
      if (requestInfo && requestInfo.headers) {
        requestInfo.headers[name] = value;
      }
      return self.originalXHR.setRequestHeader!.apply(this, arguments as any);
    };
    
    // 拦截 send 方法
    XMLHttpRequestPrototype.send = function(body?: any): void {
      const requestInfo = self.requestMap.get(this);
      if (requestInfo) {
        requestInfo.body = body;
        
        // 监听状态变化
        const stateChangeHandler = () => {
          if (this.readyState === XMLHttpRequest.DONE) {
            const endTime = Date.now();
            const duration = endTime - requestInfo.startTime;
            
            const apiData: ApiEventData = {
              method: requestInfo.method,
              url: requestInfo.url,
              status: this.status,
              statusText: this.statusText,
              duration: Math.round(duration),
              requestHeaders: requestInfo.headers,
              responseHeaders: self.parseHeaders(this.getAllResponseHeaders()),
              requestSize: self.getSize(requestInfo.body),
              responseSize: self.getSize(this.responseText),
              success: this.status >= 200 && this.status < 400
            };
            
            self.emitApiEvent(apiData);
          }
        };
        
        // 监听错误
        const errorHandler = () => {
          const endTime = Date.now();
          const duration = endTime - requestInfo.startTime;
          
          const apiData: ApiEventData = {
            method: requestInfo.method,
            url: requestInfo.url,
            status: 0,
            statusText: 'Network Error',
            duration: Math.round(duration),
            success: false,
            errorMessage: 'Network request failed'
          };
          
          self.emitApiEvent(apiData);
        };
        
        // 监听超时
        const timeoutHandler = () => {
          const endTime = Date.now();
          const duration = endTime - requestInfo.startTime;
          
          const apiData: ApiEventData = {
            method: requestInfo.method,
            url: requestInfo.url,
            status: 0,
            statusText: 'Timeout',
            duration: Math.round(duration),
            success: false,
            errorMessage: 'Request timeout'
          };
          
          self.emitApiEvent(apiData);
        };
        
        this.addEventListener('readystatechange', stateChangeHandler);
        this.addEventListener('error', errorHandler);
        this.addEventListener('timeout', timeoutHandler);
      }
      
      return self.originalXHR.send!.apply(this, arguments as any);
    };
    // #endif
  }

  /**
   * 拦截Fetch
   */
  private interceptFetch(): void {
    // #ifdef H5
    if (typeof window === 'undefined' || typeof window.fetch === 'undefined') {
      return;
    }

    const self = this;
    this.originalFetch = window.fetch;
    
    window.fetch = function(
      input: RequestInfo | URL,
      init?: RequestInit
    ): Promise<Response> {
      const startTime = Date.now();
      const url = input instanceof Request ? input.url : input.toString();
      const method = init?.method || (input instanceof Request ? input.method : 'GET');
      
      // 过滤监控上报请求
      if (url.includes(self.config.endpoint)) {
        return self.originalFetch!.apply(window, arguments as any);
      }
      
      return self.originalFetch!.apply(window, arguments as any)
        .then(async (response) => {
          const endTime = Date.now();
          const duration = endTime - startTime;
          
          // 克隆响应以便读取body
          let responseSize = 0;
          try {
            const clonedResponse = response.clone();
            const text = await clonedResponse.text();
            responseSize = self.getSize(text);
          } catch (e) {
            // 忽略读取错误
          }
          
          const apiData: ApiEventData = {
            method: method,
            url: url,
            status: response.status,
            statusText: response.statusText,
            duration: Math.round(duration),
            requestHeaders: self.normalizeHeaders(init?.headers),
            responseHeaders: self.parseHeaders(response.headers),
            requestSize: self.getSize(init?.body),
            responseSize: responseSize,
            success: response.ok
          };
          
          self.emitApiEvent(apiData);
          
          return response;
        })
        .catch((error) => {
          const endTime = Date.now();
          const duration = endTime - startTime;
          
          const apiData: ApiEventData = {
            method: method,
            url: url,
            status: 0,
            statusText: 'Network Error',
            duration: Math.round(duration),
            success: false,
            errorMessage: error.message || 'Network request failed'
          };
          
          self.emitApiEvent(apiData);
          
          throw error;
        });
    };
    // #endif
  }

  /**
   * 拦截uni.request
   */
  private interceptUniRequest(): void {
    if (typeof uni === 'undefined' || !uni.request) {
      return;
    }

    const self = this;
    this.originalUniRequest = uni.request;
    
    uni.request = function(options: any): any {
      const startTime = Date.now();
      const url = options.url || '';
      const method = (options.method || 'GET').toUpperCase();
      
      // 过滤监控上报请求
      if (url.includes(self.config.endpoint)) {
        return self.originalUniRequest!.apply(uni, arguments as any);
      }
      
      // 包装success和fail回调
      const originalSuccess = options.success;
      const originalFail = options.fail;
      const originalComplete = options.complete;
      
      options.success = function(response: any) {
        const endTime = Date.now();
        const duration = endTime - startTime;
        
        const apiData: ApiEventData = {
          method: method,
          url: url,
          status: response.statusCode || 200,
          statusText: 'OK',
          duration: Math.round(duration),
          requestHeaders: options.header || options.headers,
          responseHeaders: response.header || response.headers,
          requestSize: self.getSize(options.data),
          responseSize: self.getSize(response.data),
          success: (response.statusCode >= 200 && response.statusCode < 400)
        };
        
        self.emitApiEvent(apiData);
        
        if (originalSuccess) {
          originalSuccess(response);
        }
      };
      
      options.fail = function(error: any) {
        const endTime = Date.now();
        const duration = endTime - startTime;
        
        const apiData: ApiEventData = {
          method: method,
          url: url,
          status: error.statusCode || 0,
          statusText: error.errMsg || 'Network Error',
          duration: Math.round(duration),
          success: false,
          errorMessage: error.errMsg || 'uni.request failed'
        };
        
        self.emitApiEvent(apiData);
        
        if (originalFail) {
          originalFail(error);
        }
      };
      
      return self.originalUniRequest!.apply(uni, arguments as any);
    };
  }

  /**
   * 恢复原始方法
   */
  private restoreOriginalMethods(): void {
    // #ifdef H5
    // 恢复XMLHttpRequest
    if (typeof XMLHttpRequest !== 'undefined' && this.originalXHR.open) {
      XMLHttpRequest.prototype.open = this.originalXHR.open;
      XMLHttpRequest.prototype.send = this.originalXHR.send!;
      XMLHttpRequest.prototype.setRequestHeader = this.originalXHR.setRequestHeader!;
    }
    
    // 恢复fetch
    if (typeof window !== 'undefined' && this.originalFetch) {
      window.fetch = this.originalFetch;
    }
    // #endif
    
    // 恢复uni.request
    if (typeof uni !== 'undefined' && this.originalUniRequest) {
      uni.request = this.originalUniRequest;
    }
  }

  /**
   * 解析响应头
   */
  private parseHeaders(headers: any): Record<string, string> {
    const parsed: Record<string, string> = {};
    
    if (headers instanceof Headers) {
      headers.forEach((value, key) => {
        parsed[key] = value;
      });
    } else if (typeof headers === 'string') {
      headers.trim().split(/[\r\n]+/).forEach((line: string) => {
        const parts = line.split(': ');
        const key = parts.shift();
        if (key) {
          parsed[key] = parts.join(': ');
        }
      });
    } else if (headers && typeof headers === 'object') {
      Object.assign(parsed, headers);
    }
    
    return parsed;
  }

  /**
   * 标准化请求头
   */
  private normalizeHeaders(headers: any): Record<string, string> | undefined {
    if (!headers) return undefined;
    
    if (headers instanceof Headers) {
      const normalized: Record<string, string> = {};
      headers.forEach((value, key) => {
        normalized[key] = value;
      });
      return normalized;
    } else if (Array.isArray(headers)) {
      const normalized: Record<string, string> = {};
      for (const [key, value] of headers) {
        normalized[key] = value;
      }
      return normalized;
    } else if (typeof headers === 'object') {
      return headers as Record<string, string>;
    }
    
    return undefined;
  }

  /**
   * 获取数据大小
   */
  private getSize(data: any): number {
    if (!data) return 0;
    
    if (typeof data === 'string') {
      return new TextEncoder().encode(data).length;
    } else if (data instanceof Blob) {
      return data.size;
    } else if (data instanceof ArrayBuffer) {
      return data.byteLength;
    } else if (data instanceof FormData) {
      // FormData 大小估算（实际大小难以精确计算）
      let size = 0;
      try {
        for (const [key, value] of data.entries()) {
          size += key.length;
          if (typeof value === 'string') {
            size += value.length;
          } else if (value instanceof Blob) {
            size += value.size;
          } else {
            size += 100; // 估算值
          }
        }
      } catch (e) {
        return 1024; // 默认值
      }
      return size;
    }
    
    try {
      return new TextEncoder().encode(JSON.stringify(data)).length;
    } catch (e) {
      return 0;
    }
  }

  /**
   * 发送API事件
   */
  private emitApiEvent(apiData: ApiEventData): void {
    // 只上报慢请求或失败请求
    const shouldReport = !apiData.success || 
                        apiData.duration > 3000 || // 3秒以上的慢请求
                        apiData.status >= 400; // 错误状态码
    
    if (shouldReport) {
      this.eventBus.emit(EventType.API, {
        type: EventType.API,
        data: apiData,
        timestamp: Date.now()
      });

      if (this.config.enableDebug) {
        console.log('[NetworkCollector] API request captured:', apiData);
      }
    }
  }

  /**
   * 获取采集器状态信息
   */
  public getStatus(): { isStarted: boolean; name: string } {
    return {
      name: this.name,
      isStarted: this.isStarted
    };
  }
} 